package xinhao.lr.lr1;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author by xinhao  2021/8/24
 * 项目集( I )，称为项目集闭包(Closure of Item Sets)，每个项目集闭包对应着自动机的一个状态。
 */
public class ProductionItemSet {
    /** 记录所有创建过的项目集 */
    public static final Map<String, ProductionItemSet> allItemSet = new HashMap<>();
    public static int stateGenerate = 0;

    /**
     * 当前项目集对应的状态
     */
    private final int state;

    /**
     * 项目的集合
     */
    private final Set<ProductionItem> items;

    /**
     * 项目集的label，用来它来判断两个项目集是否相等
     */
    private final String label;

    public ProductionItemSet(int state, Set<ProductionItem> items, String label) {
        this.state = state;
        this.items = items;
        this.label = label;
    }

    public static ProductionItemSet create(Set<ProductionItem> items) {
        StringBuilder labelBuilder = new StringBuilder();
        // 这里必须进行排序，保证不同Set 集合有相同顺序，这样才能比较两个项目集
        items.stream().sorted().forEach(item -> labelBuilder.append(item.getLabel()).append(","));
        if (labelBuilder.length() != 0) {
            labelBuilder.deleteCharAt(labelBuilder.length() - 1);
        }
        String label = labelBuilder.toString();
        /**
         * 如果 label 相同，说明是同一个项目集，那么返回之前创建的；
         * 保证相同 items 的是返回的是同一个 ProductionItemSet
         */
        ProductionItemSet itemSet = allItemSet.get(label);
        if (itemSet == null) {
            itemSet = new ProductionItemSet(stateGenerate++, items, label);
            allItemSet.put(label, itemSet);
        }
        return itemSet;

    }

    public int getState() {
        return state;
    }

    public Set<ProductionItem> getItems() {
        return items;
    }

    public String getLabel() {
        return label;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ProductionItemSet itemSet = (ProductionItemSet) o;
        return Objects.equals(label, itemSet.label);
    }

    @Override
    public int hashCode() {
        return Objects.hash(label);
    }

    @Override
    public String toString() {
        return state + ":"+label;
    }
}
